package cn.iocoder.an.module.business.service.auditplan;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.an.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.an.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.an.module.business.dal.dataobject.auditarea.AuditAreaDO;
import cn.iocoder.an.module.business.dal.dataobject.auditlevel.AuditLevelDO;
import cn.iocoder.an.module.business.dal.dataobject.auditplanarea.AuditPlanAreaDO;
import cn.iocoder.an.module.business.dal.dataobject.auditplandetail.AuditPlanDetailDO;
import cn.iocoder.an.module.business.dal.dataobject.audittype.AuditConfigDO;
import cn.iocoder.an.module.business.dal.dataobject.audittype.AuditTypeDO;
import cn.iocoder.an.module.business.dal.mysql.auditarea.AuditAreaMapper;
import cn.iocoder.an.module.business.dal.mysql.auditlevel.AuditLevelMapper;
import cn.iocoder.an.module.business.dal.mysql.auditplanarea.AuditPlanAreaMapper;
import cn.iocoder.an.module.business.dal.mysql.auditplandetail.AuditPlanDetailMapper;
import cn.iocoder.an.module.business.dal.mysql.audittype.AuditConfigMapper;
import cn.iocoder.an.module.business.dal.mysql.audittype.AuditTypeMapper;
import cn.iocoder.an.module.business.utils.WeComMessageUtil;
import cn.iocoder.an.module.infra.dal.mysql.config.ConfigMapper;
import cn.iocoder.an.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.an.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.an.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.an.module.system.service.user.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.an.module.business.controller.admin.auditplan.vo.*;
import cn.iocoder.an.module.business.dal.dataobject.auditplan.AuditPlanDO;
import cn.iocoder.an.framework.common.pojo.PageResult;
import cn.iocoder.an.framework.common.util.object.BeanUtils;

import cn.iocoder.an.module.business.dal.mysql.auditplan.AuditPlanMapper;

import static cn.iocoder.an.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.an.module.business.enums.ErrorCodeConstants.*;
import static cn.iocoder.an.module.system.enums.ErrorCodeConstants.AUDIT_CONFIG_NOT_EXIST;
import static cn.iocoder.an.module.system.enums.ErrorCodeConstants.DEPT_NOT_FOUND;

/**
 * 审核计划 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class AuditPlanServiceImpl implements AuditPlanService {

    @Resource
    private AuditPlanMapper auditPlanMapper;
    @Resource
    private AuditPlanAreaMapper auditPlanAreaMapper;

    @Resource
    private AuditAreaMapper auditAreaMapper;

    @Resource
    private AuditPlanDetailMapper auditPlanDetailMapper;

    @Resource
    private AuditConfigMapper auditConfigMapper;

    @Resource
    private AuditLevelMapper auditLevelMapper;
    @Autowired
    private ConfigMapper configMapper;

    @Resource
    private AdminUserService userService;

    @Autowired
    private WeComMessageUtil weComMessageUtil;

    @Autowired
    private AuditTypeMapper auditTypeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createAuditPlan(AuditPlanSaveReqVO createReqVO) {
        // 插入
        AuditPlanDO auditPlan = BeanUtils.toBean(createReqVO, AuditPlanDO.class);
        auditPlanMapper.insert(auditPlan);
        // 插入子表
        createAuditPlanAreaList(auditPlan.getId(), auditPlan.getLevelId(), createReqVO.getAuditPlanAreas());
        // 返回
        return auditPlan.getId();
    }

    @Override
    public Boolean createAuditTask(AuditPlanSaveReqVO createReqVO) {
        Long id = createReqVO.getId();

        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();
        //所有区域
        List<AuditPlanAreaDO> auditPlanAreaListByPlanId = getAuditPlanAreaListByPlanId(id);
        //每个区域  对应多个审核项
        for (AuditPlanAreaDO auditPlanArea : auditPlanAreaListByPlanId) {
            auditPlanArea.setSendUserId(loginUserId);//下发人
            auditPlanArea.setSendUserName(loginUserNickname);
            auditPlanArea.setSendTime(LocalDateTime.now());//下发时间
            auditPlanArea.setStatus(2);//已下发

            List<Long> auditUserId = auditPlanArea.getAuditUserId();
            String auditUserName = auditPlanArea.getAuditUserName();

            //查询等级
            Long levelId = auditPlanArea.getLevelId();
            AuditLevelDO auditLevelDO = auditLevelMapper.selectById(levelId);
            //查询绑定的审核项
            List<Long> configId = auditLevelDO.getConfigId() != null ? auditLevelDO.getConfigId() : new ArrayList<>();
            configId.add(0L);
            // 1. 查询所有审核配置
            LambdaQueryWrapperX<AuditConfigDO> configQueryWrapperX = new LambdaQueryWrapperX<>();
            configQueryWrapperX.in(AuditConfigDO::getId, configId);
            List<AuditConfigDO> auditConfigDOS = auditConfigMapper.selectList(configQueryWrapperX);

            if (auditConfigDOS == null || auditConfigDOS.size() == 0) {
                throw exception(AUDIT_CONFIG_NOT_EXIST);
            }

            // 2. 提取所有 auditTypeId，去重后批量查询 AuditTypeDO
            Set<Long> auditTypeIds = auditConfigDOS.stream()
                    .map(AuditConfigDO::getAuditTypeId)
                    .filter(Objects::nonNull) // 防空
                    .collect(Collectors.toSet());

            auditTypeIds.add(0L);
            // 批量查询所有审核类型
            List<AuditTypeDO> auditTypeList = auditTypeMapper.selectBatchIds(auditTypeIds);
            // 转为 Map<id, name> 或 Map<id, AuditTypeDO>，便于快速查找
            Map<Long, String> typeNameMap = auditTypeList.stream()
                    .collect(Collectors.toMap(AuditTypeDO::getId, AuditTypeDO::getName));

            // 3. 组装结果，避免循环中查库
            List<AuditPlanDetailDO> detailDOList = auditConfigDOS.stream().map(config -> {
                String typeName = typeNameMap.get(config.getAuditTypeId());

                AuditPlanDetailDO detailDO = new AuditPlanDetailDO();
                detailDO.setAuditTypeId(config.getAuditTypeId());
                detailDO.setAuditTypeName(typeName); // 可能为 null，根据业务决定是否处理
                detailDO.setPlanAreaId(auditPlanArea.getId());
                detailDO.setConfigName(config.getName());
                detailDO.setConfigId(config.getId());
                detailDO.setAuditUserId(auditUserId);
                detailDO.setAuditUserName(auditUserName);

                return detailDO;
            }).collect(Collectors.toList());
            if (detailDOList.size() > 0) {
                auditPlanDetailMapper.insertBatch(detailDOList);
            }
            sendMessage(auditPlanArea.getAuditUserId(),auditPlanArea.getAreaName());

        }

        //批量更新
        if (auditPlanAreaListByPlanId.size() > 0) {
            auditPlanAreaMapper.updateBatch(auditPlanAreaListByPlanId);
        }

        AuditPlanDO auditPlanDO = auditPlanMapper.selectById(id);

        if (auditPlanDO != null) {
            auditPlanDO.setSnedUserId(SecurityFrameworkUtils.getLoginUserId());
            auditPlanDO.setStatus(2);
            //更新状态 已下发
            auditPlanMapper.updateById(auditPlanDO);

        }

        return true;
    }


    public void sendMessage(List<Long> dutyUserId,String deptName) {
        //推送消息
        List<AdminUserDO> userList = userService.getUserList(dutyUserId);
        String userIds = "";
        StringBuilder userIdBuilder = new StringBuilder();


        // 获取当前时间并格式化
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedNow = now.format(formatter);

        for (AdminUserDO user : userList) {
            String userId = weComMessageUtil.getUserIdByMobile(user.getEnterpriseWeChatAccount());
            if (userId != null && !userId.trim().isEmpty()) {
                // 如果已经有内容了，先添加分隔符
                if (userIdBuilder.length() > 0) {
                    userIdBuilder.append("|");
                }
                userIdBuilder.append(userId);
            }
        }

        // 将 StringBuilder 转换为最终的字符串
        userIds = userIdBuilder.toString();
        // 可选：检查最终结果是否为空
        if (userIds.isEmpty()) {
            // 处理没有找到任何有效用户ID的情况
            System.out.printf("没有找到任何有效的企业微信 UserID");
            return;
        }

        // 1. 使用 sendTextMessage 方法 (更灵活，可以同时指定用户、部门、标签)

        String text = "您有新的分层审核任务,区域: " + deptName +",请注意";

        String systemMessage = text + formattedNow;
        // 将时间戳添加到消息中
        WeComMessageUtil.WeComSendResult weComSendResult = weComMessageUtil.sendTextMessage(systemMessage, userIds, null, null);
        System.out.printf("推送结果:" + weComSendResult.toString());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAuditPlan(AuditPlanSaveReqVO updateReqVO) {
        // 校验存在
        validateAuditPlanExists(updateReqVO.getId());
        // 更新
        AuditPlanDO updateObj = BeanUtils.toBean(updateReqVO, AuditPlanDO.class);
        auditPlanMapper.updateById(updateObj);

        // 更新子表
        updateAuditPlanAreaList(updateReqVO.getId(), updateReqVO.getAuditPlanAreas());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAuditPlan(Long id) {
        // 校验存在
        validateAuditPlanExists(id);
        // 删除
        auditPlanMapper.deleteById(id);

        // 删除子表
        deleteAuditPlanAreaByPlanId(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAuditPlanListByIds(List<Long> ids) {
        // 删除
        auditPlanMapper.deleteByIds(ids);

        // 删除子表
        deleteAuditPlanAreaByPlanIds(ids);
    }


    private void validateAuditPlanExists(Long id) {
        if (auditPlanMapper.selectById(id) == null) {
            throw exception(AUDIT_PLAN_NOT_EXISTS);
        }
    }

    @Override
    public AuditPlanDO getAuditPlan(Long id) {
        return auditPlanMapper.selectById(id);
    }

    @Override
    public PageResult<AuditPlanDO> getAuditPlanPage(AuditPlanPageReqVO pageReqVO) {
        return auditPlanMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（审核计划区域） ====================

    @Override
    public List<AuditPlanAreaDO> getAuditPlanAreaListByPlanId(Long planId) {
        return auditPlanAreaMapper.selectListByPlanId(planId);
    }

    @Override
    public List<AuditPlanAreaDO> getAuditAreaList() {
        List<AuditAreaDO> auditAreaDOS = auditAreaMapper.selectList();
        List<AuditPlanAreaDO> resultList = new ArrayList<>();
        for (AuditAreaDO areaDO : auditAreaDOS) {
            AuditPlanAreaDO auditPlanAreaDO = new AuditPlanAreaDO();
            auditPlanAreaDO.setAreaId(areaDO.getId());
            auditPlanAreaDO.setAreaName(areaDO.getDeptName());
            List<Long> audit = new ArrayList<>();
            audit.add(areaDO.getDutyUserId());
            auditPlanAreaDO.setAuditUserId(audit);
            resultList.add(auditPlanAreaDO);
        }
        return resultList;
    }

    private void createAuditPlanAreaList(Long planId, Long levelId, List<AuditPlanAreaDO> list) {
        for (AuditPlanAreaDO planAreaDO : list) {
            planAreaDO.setPlanId(planId);
            planAreaDO.setLevelId(levelId);
            //设置维修人并推送消息
            List<Long> dutyUserId = planAreaDO.getAuditUserId();
            List<AdminUserDO> userList = userService.getUserList(dutyUserId);
            String dutyUserName = userList.stream()
                    .map(AdminUserDO::getNickname)                    // 提取 nickname
                    .filter(nickname -> nickname != null && !nickname.trim().isEmpty()) // 过滤 null/空
                    .collect(Collectors.joining(","));               // 用逗号拼接
            planAreaDO.setAuditUserName(dutyUserName);
        }
        auditPlanAreaMapper.insertBatch(list);
    }

    private void updateAuditPlanAreaList(Long planId, List<AuditPlanAreaDO> list) {
        for (AuditPlanAreaDO planAreaDO : list) {
            planAreaDO.setPlanId(planId);
            //设置维修人并推送消息
            List<Long> dutyUserId = planAreaDO.getAuditUserId();
            List<AdminUserDO> userList = userService.getUserList(dutyUserId);
            String dutyUserName = userList.stream()
                    .map(AdminUserDO::getNickname)                    // 提取 nickname
                    .filter(nickname -> nickname != null && !nickname.trim().isEmpty()) // 过滤 null/空
                    .collect(Collectors.joining(","));               // 用逗号拼接
            planAreaDO.setAuditUserName(dutyUserName);
        }
        List<AuditPlanAreaDO> oldList = auditPlanAreaMapper.selectListByPlanId(planId);
        List<List<AuditPlanAreaDO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
            boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
            if (same) {
                newVal.setId(oldVal.getId()).clean(); // 解决更新情况下：updateTime 不更新
            }
            return same;
        });

        // 第二步，批量添加、修改、删除
        if (CollUtil.isNotEmpty(diffList.get(0))) {
            auditPlanAreaMapper.insertBatch(diffList.get(0));
        }
        if (CollUtil.isNotEmpty(diffList.get(1))) {
            auditPlanAreaMapper.updateBatch(diffList.get(1));
        }
        if (CollUtil.isNotEmpty(diffList.get(2))) {
            auditPlanAreaMapper.deleteByIds(convertList(diffList.get(2), AuditPlanAreaDO::getId));
        }
    }

    private void deleteAuditPlanAreaByPlanId(Long planId) {
        auditPlanAreaMapper.deleteByPlanId(planId);
    }

    private void deleteAuditPlanAreaByPlanIds(List<Long> planIds) {
        auditPlanAreaMapper.deleteByPlanIds(planIds);
    }

}